namespace Rsdn.TreeGrid
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Drawing;
    using System.Windows.Forms;

    /// <summary>
    /// Этот класс кэширует ресурсы вроде шрифтов на время отрисовки.
    /// Если отрисовка происходит для отдельных ячеек грида или разорвана
    /// в следствии каких-то других причин, перехватите сообщение WM_PAINT
    /// и перед его стандартной обработкой создайте экземлпяр данного класса.
    /// После окончания стандартной отрисовки вызовите Dispose() этому экземпляру.
    /// </summary>
    internal class PaintCache : IDisposable
    {
        /// <summary>
        /// Временный кэш для хэндлов шрифтов. Очищается в Dispose().
        /// </summary>
        private readonly Dictionary<Font, IntPtr> _globalFontMap = new Dictionary<Font, IntPtr>();
        /// <summary>
        /// Последний использованный цвет текста. Если он не изменялся,
        /// используется предыдущий цвет выбранный в контексте отрисовки.
        /// </summary>
        private Color _lastForeColor;

        public void Dispose()
        {
            foreach (IntPtr ptr in this._globalFontMap.Values)
            {
                Rsdn.TreeGrid.NativeMethods.DeleteObject(ptr);
            }
            this._lastForeColor = Color.Empty;
        }

        /// <summary>
        /// Отрисовывает текст с соотвествующим форматриованием.
        /// Прочтите описание класса перед перед использованием этого метода!
        /// </summary>
        /// <param name="dc">Контекст отрисовки.</param>
        /// <param name="text">Выводимый текст.</param>
        /// <param name="font">Шрифт которым будет производиться отрисовка.</param>
        /// <param name="foreColor">Цвет которым будет выводиться текст.</param>
        /// <param name="rect">Область в конткроле в которую будет выведен текст.
        /// </param>
        /// <param name="format">Настройки формата (выравниваине...).</param>
        public void DrawText(IDeviceContext dc, string text, Font font, Color foreColor, Rectangle rect, TextFormatFlags format)
        {
            IntPtr ptr;
			if ((format & TextFormatFlags.Right) == TextFormatFlags.Right)
            {
                rect.Width -= 2;
            }
            Trace.Assert(font != null);
            IntPtr hdc = dc.GetHdc();
            if (!this._globalFontMap.TryGetValue(font, out ptr))
            {
                if (font != null)
                {
                    ptr = font.ToHfont();
                }
                this._globalFontMap.Add(font, ptr);
            }
            using (new GdiSelectorHelper(hdc, ptr))
            {
                if (this._lastForeColor != foreColor)
                {
                    int crColor = ColorTranslator.ToWin32(foreColor);
                    Rsdn.TreeGrid.NativeMethods.SetTextColor(hdc, crColor);
                    this._lastForeColor = foreColor;
                }
                Rsdn.TreeGrid.NativeMethods.RECT lpRect = rect;
                if (text != null)
                {
                    Rsdn.TreeGrid.NativeMethods.DrawText(hdc, text, text.Length, ref lpRect, (uint)(format | TextFormatFlags.NoPrefix));
                }
            }
            dc.ReleaseHdc();
        }

        /// <summary>
        /// Рисует прямоугольник заданным цветом. Т.е. вывод текста на фоне, но без текста.
        /// </summary>
        /// <param name="dc">контекст устройства</param>
        /// <param name="rect">Прямоугольник для закрашивания</param>
        /// <param name="backColor">Цвет для закрашивания</param>
        public void FillSolidRect(IDeviceContext dc, Rectangle rect, Color backColor)
        {
            IntPtr hdc = dc.GetHdc();
			NativeMethods.RECT textRect = rect;
			int oldColor = NativeMethods.SetBkColor(hdc, ColorTranslator.ToWin32(backColor));
            try
            {
				// ,ЙУ?*"%№"!!!!!!! 
				// Что за бесовщина????? кто выбранные объкты удалять будет?
				/*
                // 2 == ETO_OPAQUE
                if (!NativeMethods.ExtTextOut(hdc, 0, 0, 2, ref textRect, null, 0, null))
                    throw new Win32Exception();
                */
				NativeMethods.ExtTextOut(hdc, 0, 0, 2, ref textRect, null, 0, null);
            }
            finally
            {
				NativeMethods.SetBkColor(hdc, oldColor);
                dc.ReleaseHdc();
            }
        }
    }
}

